package com.richfit.cuba.modular.lsms.uploadFile.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.security.cert.CertificateEncodingException;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.richfit.cuba.modular.lsms.entity.SafeTampering;
import com.richfit.cuba.modular.lsms.mapper.SafeTamperingMapper;
import com.richfit.cuba.modular.lsms.uploadFile.entity.UkeyUploadfile;
import com.richfit.cuba.modular.lsms.uploadFile.mapper.UkeyUploadfileMapper;
import com.richfit.cuba.modular.lsms.uploadFile.service.IUkeyUploadfileService;
import com.richfit.cuba.modular.lsms.uploadFile.util.CertificateType;
import com.richfit.cuba.modular.lsms.util.DateUtils;
import com.richfit.cuba.web.core.shiro.ShiroKit;
import com.richfit.cuba.web.core.shiro.ShiroUser;

import cn.hutool.core.io.FileUtil;
import sun.misc.BASE64Encoder;

/**
 * <p>
 * 证书上传 服务实现类
 * </p>
 *
 * @author Alan
 * @since 2018-11-07
 */
@Service
@Transactional
public class UkeyUploadfileServiceImpl extends ServiceImpl<UkeyUploadfileMapper, UkeyUploadfile> implements IUkeyUploadfileService {
	
	private final String CERT_SUFFIX = ".cer";
	private final String P12_SUFFIX = ".p12";
	
	@Autowired
	private SafeTamperingMapper safeTamperingMapper;
	/**   
	 * <p>Title: findPage</p>   
	 * <p>Description: </p>   
	 * @param page
	 * @param condition
	 * @return   
	 * @see com.richfit.cuba.modular.lsms.uploadFile.service.IUkeyUploadfileService#findPage(com.baomidou.mybatisplus.plugins.Page, java.lang.String)   
	 * @author: Alan
	 * @date:   2019-02-28 21:22:07
	 */
	@Override
	public Page<UkeyUploadfile> findPageForUkey(Page<UkeyUploadfile> page, String condition) {
    	QueryWrapper<UkeyUploadfile> entity = new QueryWrapper<UkeyUploadfile>();
    	entity.eq("CERTIFICATE_TYPE", CertificateType.CERTIFICATE_TYPE_UKEY);
    	if(StringUtils.isNotBlank(condition)) {
    		entity.like("USER_NAME", condition);
    	}
    	return (Page<UkeyUploadfile>) page(page,entity);
	}
	
	/**   
	 * <p>Title: saveUpload</p>   
	 * <p>Description: </p>   
	 * @param uploadFile
	 * @return   
	 * @see com.richfit.cuba.modular.lsms.uploadFile.service.IUkeyUploadfileService#saveUpload(com.richfit.cuba.modular.lsms.uploadFile.entity.UkeyUploadfile)   
	 * @author: Alan
	 * @throws IOException 
	 * @throws CertificateException 
	 * @date:   2019-04-07 10:09:40
	 */
	@Override
	public boolean saveUpload(UkeyUploadfile ukeyUploadfile, int certificateType) throws Exception {
		boolean flag = false;
		Date date=DateUtils.getCubaDate(Calendar.getInstance().getTime());
		
		ShiroUser user = ShiroKit.getUser();
    	ukeyUploadfile.setUpdateDate(date);
    	ukeyUploadfile.setCertificateType(certificateType);
    	ukeyUploadfile.setCreateBy(user.getId().toString());
    	ukeyUploadfile.setUpdateBy(user.getId().toString());
    	// cert begin and end time
    	if(StringUtils.isNotBlank(ukeyUploadfile.getCertificatePath())) {
    		if(certificateType == CertificateType.CERTIFICATE_TYPE_UKEY 
    				|| ukeyUploadfile.getCertificatePath().toLowerCase().contains(this.CERT_SUFFIX)) {
	    		X509Certificate oCert = getCertObject(ukeyUploadfile.getCertificatePath());
	    		ukeyUploadfile.setNotBeforeTime(oCert.getNotBefore());
	    		ukeyUploadfile.setNotAfterTime(oCert.getNotAfter());
    		}else if(ukeyUploadfile.getCertificatePath().toLowerCase().contains(this.P12_SUFFIX)) {
    			
    			String password = ukeyUploadfile.getCertificatePasswrd();
    			KeyStore ks = getKeyStore(ukeyUploadfile.getCertificatePath(), password);
    			Certificate cert = getCertificate(ks);
    			X509Certificate oCert = X509Certificate.getInstance(cert.getEncoded());
    			ukeyUploadfile.setNotBeforeTime(oCert.getNotBefore());
	    		ukeyUploadfile.setNotAfterTime(oCert.getNotAfter());
	    		// 保存防篡改证书
	    		List<SafeTampering> list = safeTamperingMapper.selectList(new QueryWrapper<SafeTampering>());
	    		SafeTampering safeTampering=null;
	    		if(CollectionUtils.isEmpty(list)) {
	    			safeTampering = new SafeTampering();
	    			safeTampering.setCreateDate(date);
	    		} else {
	    			safeTampering = list.get(0);
	    		}
	    		safeTampering.setPublicKey(getCertStr(oCert));
	    		safeTampering.setPrivateKey(getPrivateKeyStr(ukeyUploadfile.getCertificatePath(), password));
	    		safeTampering.setUpdateDate(date);
	    		safeTampering.setDelFlag("0");
	    		if(StringUtils.isBlank(safeTampering.getId())) {
	    			safeTamperingMapper.insert(safeTampering);
	    		} else {
	    			safeTamperingMapper.updateById(safeTampering);
	    		}
    		}
    	}
    	
    	// update
    	if(ukeyUploadfile!=null && StringUtils.isNotBlank(ukeyUploadfile.getId())) {
    		flag = updateById(ukeyUploadfile);
    	}else {
			ukeyUploadfile.setCreateDate(date);
			flag = save(ukeyUploadfile);
    	}
		return flag;
	}



	@Override
	public String uploadFile(HttpServletRequest request, HttpServletResponse response,String localPath ) {
		// 初始化通用multipart解析器
		String path = ""; // 路径加名称
		String fileName = "";// 图片名称
		// 解析请求，将文件信息放到迭代器里
		MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
		Iterator<String> iter = multiRequest.getFileNames();
		// 迭代文件，存放到某一路径里
		while (iter.hasNext()) {
			// 取得上传文件
			MultipartFile file = multiRequest.getFile(iter.next());
			try {
				if (null != file) {
					// 取得当前上传文件的文件名称
					String myFileName = file.getOriginalFilename();
					// 判断文件是否存在，文件名为空，则说明文件不
					if (myFileName.trim() != "") {
						// 重命名上传后的文件名
						fileName = this.getName(myFileName);
						// 定义上传路径
						File localFilePath = new File(localPath);
						if (!localFilePath.exists() && !localFilePath.isDirectory()) {
							localFilePath.mkdir();
						}
						path=localPath+"/"+fileName;
						File localFile = new File(path);
						file.transferTo(localFile);
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
				path="";
			}

		}
		return path;
	}

	private String getName(String myFileName) {
		// 获取一个50以内的随机值
		Random ra = new Random();
		int raNum = ra.nextInt(100);
		// 获取当前系统时间
		// Long nowTime =System.currentTimeMillis();
		SimpleDateFormat formater = new SimpleDateFormat("yyMMdd");
		String nowTime = formater.format(Calendar.getInstance().getTime());
		String resultName = nowTime + "" + raNum + myFileName;
		return resultName;

	}
	
	public boolean isBind(String ukeyUploadfileId) {
		UkeyUploadfile data = getById(ukeyUploadfileId);
		boolean isTrue = true;
		if(data.getIsBind()==0) {
			isTrue = false;
		}
		return isTrue;
	}
	
	public boolean deleteFile(String ukeyUploadfileId) {
		UkeyUploadfile data = getById(ukeyUploadfileId);
		boolean isTrue = false;
		if(data.getIsBind()==0) {
			isTrue = FileUtil.del(data.getCertificatePath());
			if(isTrue) {
				isTrue = removeById(ukeyUploadfileId);
			}
		}
		return isTrue;
	}
	
	private X509Certificate getCertObject(String filePath) throws  IOException, CertificateException {
		// 读取证书文件
		InputStream inStream = new FileInputStream(filePath);
		// 创建证书对象
		X509Certificate oCert = X509Certificate.getInstance(inStream);
		inStream.close();
		return oCert;
	}
	
	private KeyStore getKeyStore(String file,String password) throws KeyStoreException, NoSuchAlgorithmException, java.security.cert.CertificateException, IOException {
		KeyStore ks = KeyStore.getInstance("PKCS12");
		FileInputStream fis = new FileInputStream(file);
		char[] nPassword = password.toCharArray();
		ks.load(fis, nPassword);
		fis.close();
		return ks;
	}
	
	private Certificate getCertificate(KeyStore ks) throws Exception {
		Enumeration<String> enum1 = ks.aliases();
		String keyAlias = null;
		if (enum1.hasMoreElements()) // we are readin just one certificate.
		{
			keyAlias = enum1.nextElement();
		}
		Certificate cert = ks.getCertificate(keyAlias);
		return cert;
	}
	
	
	private String getCertStr(X509Certificate oCert) {
		try {
			BASE64Encoder base64Encoder = new BASE64Encoder();
			return base64Encoder.encode(oCert.getEncoded());
		} catch (CertificateEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private String getPrivateKeyStr(String file,String password){
		String pk = null;
		try {
			KeyStore ks = getKeyStore(file, password);
			Enumeration<String> enum1 = ks.aliases();
			String keyAlias = null;
			if (enum1.hasMoreElements()) // we are readin just one certificate.
			{
				keyAlias = (String) enum1.nextElement();
			}
			char[] nPassword = password.toCharArray();
			PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias, nPassword);
			
			BASE64Encoder base64Encoder = new BASE64Encoder();
			pk = base64Encoder.encode(prikey.getEncoded());
		} catch (IOException | UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException | java.security.cert.CertificateException e) {
			e.printStackTrace();
		}
		return pk;
	}
	
}
